package socks

import (
	"encoding/binary"
	"errors"
	"fmt"
	"gitee.com/simple-set/simple.io/src/event"
	"gitee.com/simple-set/simple.io/src/process/codec"
	"net"
)

// Version 协议版本
type Version byte

const (
	V4 Version = 4
	V5 Version = 5
)

// AddrType 目标地址类型
type AddrType byte

const (
	IpV4   AddrType = 1
	Ipv6   AddrType = 4
	Domain AddrType = 3
)

// Cmd 命令类型
type Cmd byte

const (
	Connect   Cmd = 1
	Bind      Cmd = 2
	Associate Cmd = 3
)

type Request struct {
	Version     Version        // 协议版本
	Cmd         Cmd            // 命令
	DstAddrType AddrType       // 目标地址类型
	DstAddr     []byte         // 目标地址
	DstPort     uint16         // 目标端口
	buff        *codec.ByteBuf // io缓冲区
	handshake   *Handshake     // 握手对象
	session     *event.Session
}

func NewRequest(handshake *Handshake, session *event.Session) *Request {
	return &Request{handshake: handshake, buff: handshake.buff, session: session}
}

func (r *Request) Buff() *codec.ByteBuf {
	return r.buff
}

func (r *Request) Session() *event.Session {
	return r.session
}

func (r *Request) GetDstAddr() *net.TCPAddr {
	if r.DstAddrType == Domain {
		return nil
	}
	return &net.TCPAddr{IP: r.DstAddr, Port: int(r.DstPort)}
}

func (r *Request) GetDstAddrString() string {
	if r.DstAddrType != Domain {
		return r.GetDstAddr().String()
	}
	return fmt.Sprintf("%s:%d", r.DstAddr, r.DstPort)
}

// Decoder 解码器, 从缓冲区读取数据解析协议, RFC1928 https://datatracker.ietf.org/doc/html/rfc1928
func (r *Request) Decoder() error {
	// 解析版本
	if readByte, err := r.buff.ReadByte(); err != nil {
		return err
	} else {
		r.Version = Version(readByte)
	}
	if r.handshake != nil && r.Version != r.handshake.version {
		return fmt.Errorf("inconsistent with handshake protocol, %c, %c", r.Version, r.handshake.version)
	}

	// 解析指令
	if readByte, err := r.buff.ReadByte(); err != nil {
		return err
	} else {
		r.Cmd = Cmd(readByte)
	}

	// RSV 保留字段, 丢弃
	if _, err := r.buff.ReadByte(); err != nil {
		return err
	}

	// 解析目标地址类型
	if readByte, err := r.buff.ReadByte(); err != nil {
		return err
	} else {
		r.DstAddrType = AddrType(readByte)
	}
	if r.DstAddrType != IpV4 && r.DstAddrType != Ipv6 && r.DstAddrType != Domain {
		return errors.New(fmt.Sprint("AddrType target type: ", r.DstAddrType))
	}

	// 解析目标地址
	if r.DstAddrType == IpV4 {
		r.DstAddr = make([]byte, 4)
		if n, err := r.buff.Read(r.DstAddr); err != nil {
			return err
		} else if n != 4 {
			return errors.New(fmt.Sprint("DstAddr size error: ", n))
		}
	}
	if r.DstAddrType == Ipv6 {
		r.DstAddr = make([]byte, 16)
		if n, err := r.buff.Read(r.DstAddr); err != nil {
			return err
		} else if n != 16 {
			return errors.New(fmt.Sprint("DstAddr size error: ", n))
		}
	}
	if r.DstAddrType == Domain {
		domainLen, err := r.buff.ReadByte()
		if err != nil {
			return err
		}
		if r.DstAddr, err = r.buff.ReadBytes(int(domainLen)); err != nil {
			return err
		}
	}

	// 解析端口
	if bytes, err := r.buff.ReadBytes(2); err != nil {
		return err
	} else {
		r.DstPort = binary.BigEndian.Uint16(bytes[:2])
	}
	return nil
}

// Encode 编码器
func (r *Request) Encode() []byte {
	return nil
}
